﻿using System;
using System.Globalization;
using System.Security.Principal;
using System.Web.Mvc;
using System.Web.Security;
using HooIzDat.Web.Helpers;
using HooIzDat.Web.Models;
using HooIzDat.Web.Services;

namespace HooIzDat.Web.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public IFormsAuthenticationService FormsAuthService { get; private set; }
        public IMembershipService MembershipService { get; private set; }
        public IPlayerRepository Players { get; private set; }

        public HomeController()
            : this(null, null, null)
        { }

        public HomeController(IFormsAuthenticationService formsAuth, IMembershipService membership, IPlayerRepository players)
        {
            FormsAuthService = formsAuth ?? new FormsAuthenticationService();
            MembershipService = membership ?? new AccountMembershipService();
            Players = players ?? new PlayerRepository();

            ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
        }

        public ActionResult About()
        {
            return View();
        }

        public ActionResult Index()
        {
            if (User.Identity.IsAuthenticated)
                return RedirectToAction("Lobby", "Games");

            return View();
        }

        public ActionResult Prize()
        {
            return View();
        }

        [HttpPost]
        public ActionResult LogOn(LogOnModel logon, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (MembershipService.ValidateUser(logon.UserName, logon.Password))
                {
                    FormsAuthService.SignIn(logon.UserName, logon.RememberMe);
                    if (!String.IsNullOrEmpty(returnUrl))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Lobby", "Games");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "The user name or password provided is incorrect.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View("Index", new IndexModel { LogOn = logon });
        }

        public ActionResult LogOff()
        {
            FormsAuthService.SignOut();
            return RedirectToAction("Index", "Home");
        }

        [HttpPost]
        public ActionResult Register(RegisterModel registration)
        {
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                MembershipCreateStatus createStatus = MembershipService.CreateUser(registration.UserName, registration.Password, registration.Email);

                if (createStatus == MembershipCreateStatus.Success)
                {
                    FormsAuthService.SignIn(registration.UserName, false /* createPersistentCookie */);
                    Players.Add(new Player { UserName = registration.UserName });
                    Players.Save();
                    return RedirectToAction("Lobby", "Games");
                }
                else
                {
                    ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
                }
            }

            // If we got this far, something failed, redisplay form
            ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
            return View("Index", new IndexModel { Registration = registration });
        }


        [Authorize]
        public ActionResult ChangePassword()
        {
            return View();
        }

        [Authorize]
        [HttpPost]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "Exceptions result in password not being changed.")]
        public ActionResult ChangePassword(string currentPassword, string newPassword, string confirmPassword)
        {
            if (!ValidateChangePassword(currentPassword, newPassword, confirmPassword))
            {
                return View();
            }

            try
            {
                if (MembershipService.ChangePassword(User.Identity.Name, currentPassword, newPassword))
                {
                    return RedirectToAction("ChangePasswordSuccess");
                }
                else
                {
                    ModelState.AddModelError("_FORM", "The current password is incorrect or the new password is invalid.");
                    return View();
                }
            }
            catch
            {
                ModelState.AddModelError("_FORM", "The current password is incorrect or the new password is invalid.");
                return View();
            }
        }

        public ActionResult ChangePasswordSuccess()
        {
            return View();
        }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.User.Identity is WindowsIdentity)
            {
                throw new InvalidOperationException("Windows authentication is not supported.");
            }
        }

        #region Validation Methods

        private bool ValidateChangePassword(string currentPassword, string newPassword, string confirmPassword)
        {
            if (String.IsNullOrEmpty(currentPassword))
            {
                ModelState.AddModelError("currentPassword", "Current password is required");
            }
            if (newPassword == null || newPassword.Length < MembershipService.MinPasswordLength)
            {
                ModelState.AddModelError("newPassword",
                    String.Format(CultureInfo.CurrentCulture,
                         "New password ≥ {0} characters is required",
                         MembershipService.MinPasswordLength));
            }

            if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal))
            {
                ModelState.AddModelError("_FORM", "Passwords do not match");
            }

            return ModelState.IsValid;
        }

        private bool ValidateLogOn(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("logonUsername", "Username is required");
            }
            if (String.IsNullOrEmpty(password))
            {
                ModelState.AddModelError("logonPassword", "Password is required");
            }
            if (!MembershipService.ValidateUser(userName, password))
            {
                ModelState.AddModelError("_FORM", "Login failed");
            }

            return ModelState.IsValid;
        }

        private bool ValidateRegistration(string userName, string email, string password, string confirmPassword)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("registerUsername", "Username is required");
            }
            if (String.IsNullOrEmpty(email))
            {
                ModelState.AddModelError("registerEmail", "Email is required");
            }
            if (password == null || password.Length < MembershipService.MinPasswordLength)
            {
                ModelState.AddModelError("registerPassword",
                    String.Format(CultureInfo.CurrentCulture,
                         "Password ≥ {0} characters is required",
                         MembershipService.MinPasswordLength));
            }
            if (!String.Equals(password, confirmPassword, StringComparison.Ordinal))
            {
                ModelState.AddModelError("_FORM", "Passwords do not match");
            }
            return ModelState.IsValid;
        }

       
        #endregion
    }
}
